Classification des articles du monde en fonction de leur contenu
Nous souhaitons classifier un article du monde selon son contenu, Nous possèdons pour cela un jeu de données avec la catégorie et le contenu de 10k articles.
Pour mener notre tâche à bien nous allons effectuer un prétraitement des données textuelles par la transformation de données (textuelles) non structurées en un format de données structuré.
Et ce dans l’objectif d’appliquer des algorithmes de classifications, cela inclut la pondération et la sélection des variables(des mots).
Concrètement, il s’agit de la transformation d’un grand nombre de caractéristiques éparses en un nombre significativement plus petit de caractéristiques denses.
Nous utiliserons ainsi 3 algorithmes pour la classification dont un dans une version limitée à 25 variables explicatives.
Nous finirons par l’évaluation des résultats de la prédiction des classifications sur le jeu de test.
On utilise l’encodage UTF-8 car le monde est un journal français utilisant des caractères spéciaux. Le jeu de test est fournis, il a pour élément positif le fait d’être un article de type économie
data <-
read.csv("le_monde.csv", encoding="UTF-8", sep=";", comment.char="#")
test <-
read.csv("lignes_jeux_tests.csv")
Il est nécessaire de transformer ces données, nous n’avons qu’une unique variable explicative : le texte en entier de l’article. Cette unique variable explicative est inexploitable, nous souhaitons un “bag of words”.
Suppression des deux collones non utiles à la modélisation
data$date <- NULL
data$title <- NULL
Pour la gestion des manquants, on supprime les lignes avec des valeurs manquantes (normalement aucune supprimmé)
## integer(0)
On applique les bons types de variables
data$category <- as.factor(data$category)
data$content <- as.character(data$content)
str(data)
## 'data.frame': 10000 obs. of 2 variables:
## $ category: Factor w/ 6 levels "culture","economie",..: 6 5 5 2 5 5 5 5 1 5 ...
## $ content : chr " / L’international français Jérémy Ménez va rejoindre le club de Bordeaux en Ligue 1, en provenance du Milan A"| __truncated__ " / Le cousin d’un des assassins du Père Jacques Hamel à Saint-Etienne-du-Rouvray, identifié comme étant Farid "| __truncated__ " / Si le premier ministre Manuel Valls constate que « l’islam a trouvé sa place dans la République », « face à"| __truncated__ " / Les épargnants français sont choyés. Lundi 1er août, le taux de rémunération du Livret A aurait théoriqueme"| __truncated__ ...
On retire les accents, en effet dans l’une des étapes suivantes où l’on retire les caractères qui ne sont pas des lettres, les lettres avec accents font des trous dans les mots, rendant un grand nombre de mots inexploitable.
On a besoin d’un objet de type corpus, on prend là ou sont les données, ici la collone V6. On affiche la première ligne
contenu <- Corpus(VectorSource(data$content))
contenu[1]$content
## [1] " / L'international francais Jeremy Menez va rejoindre le club de Bordeaux en Ligue 1, en provenance du Milan AC, sous reserve de la traditionnelle visite medicale, a annonce le club aquitain dimanche. / Menez est la troisieme recrue des Girondins apres le milieu de Monaco, Jeremy Toulalan, et l'attaquant guineen de Bastia, Francois Kamano. Bordeaux sort d'une pale saison et repart avec des ambitions nouvelles et l'entraineur Jocelyn Gourvennec, qui jouit d'une grosse cote grace a ses six saisons convaincantes a Guingamp. Age de 29 ans, Menez, qui compte 24 selections (2 buts) chez les Bleus -la derniere en 2013-, evoluait depuis deux ans au Milan AC, ou il lui restait un an de contrat, mais sa derniere saison a ete perturbee par des blessures. Forme a Sochaux, Menez fait partie de la fameuse generation 1987 championne d'Europe des U17 en 2004. Alors considere comme un des plus grands espoirs du foot francais, il avait par la suite rejoint Monaco de 2006 a 2008, puis la Roma pendant quatre saisons avant de revenir en France, au Paris-Saint-Germain en 2012. Son aventure parisienne, avec deux titres de champion a la cle, avait pris fin deux ans plus tard pour un retour en Italie, au Milan AC. Au sein de l'equipe lombarde il a realise sa meilleure saison (16 buts inscrits) en 2014-2015, avant d'etre perturbe par des blessures au dos la saison derniere qui l'ont prive de sept mois de competition, d'aout a janvier, pour ne disputer que 10 matchs (2 buts)."
On supprime les caracteres qui ne sont pas des lettres (cette étape posait problème avec les lettres à accent)
contenu <- tm_map(contenu, content_transformer(gsub), pattern = "[^a-zA-Z]", replacement = " ")
## Warning in tm_map.SimpleCorpus(contenu, content_transformer(gsub), pattern =
## "[^a-zA-Z]", : transformation drops documents
contenu[1]$content
## [1] " L international francais Jeremy Menez va rejoindre le club de Bordeaux en Ligue en provenance du Milan AC sous reserve de la traditionnelle visite medicale a annonce le club aquitain dimanche Menez est la troisieme recrue des Girondins apres le milieu de Monaco Jeremy Toulalan et l attaquant guineen de Bastia Francois Kamano Bordeaux sort d une pale saison et repart avec des ambitions nouvelles et l entraineur Jocelyn Gourvennec qui jouit d une grosse cote grace a ses six saisons convaincantes a Guingamp Age de ans Menez qui compte selections buts chez les Bleus la derniere en evoluait depuis deux ans au Milan AC ou il lui restait un an de contrat mais sa derniere saison a ete perturbee par des blessures Forme a Sochaux Menez fait partie de la fameuse generation championne d Europe des U en Alors considere comme un des plus grands espoirs du foot francais il avait par la suite rejoint Monaco de a puis la Roma pendant quatre saisons avant de revenir en France au Paris Saint Germain en Son aventure parisienne avec deux titres de champion a la cle avait pris fin deux ans plus tard pour un retour en Italie au Milan AC Au sein de l equipe lombarde il a realise sa meilleure saison buts inscrits en avant d etre perturbe par des blessures au dos la saison derniere qui l ont prive de sept mois de competition d aout a janvier pour ne disputer que matchs buts "
On mets les majuscules en minuscules
contenu <- tm_map(contenu, content_transformer(tolower))
## Warning in tm_map.SimpleCorpus(contenu, content_transformer(tolower)):
## transformation drops documents
contenu[1]$content
## [1] " l international francais jeremy menez va rejoindre le club de bordeaux en ligue en provenance du milan ac sous reserve de la traditionnelle visite medicale a annonce le club aquitain dimanche menez est la troisieme recrue des girondins apres le milieu de monaco jeremy toulalan et l attaquant guineen de bastia francois kamano bordeaux sort d une pale saison et repart avec des ambitions nouvelles et l entraineur jocelyn gourvennec qui jouit d une grosse cote grace a ses six saisons convaincantes a guingamp age de ans menez qui compte selections buts chez les bleus la derniere en evoluait depuis deux ans au milan ac ou il lui restait un an de contrat mais sa derniere saison a ete perturbee par des blessures forme a sochaux menez fait partie de la fameuse generation championne d europe des u en alors considere comme un des plus grands espoirs du foot francais il avait par la suite rejoint monaco de a puis la roma pendant quatre saisons avant de revenir en france au paris saint germain en son aventure parisienne avec deux titres de champion a la cle avait pris fin deux ans plus tard pour un retour en italie au milan ac au sein de l equipe lombarde il a realise sa meilleure saison buts inscrits en avant d etre perturbe par des blessures au dos la saison derniere qui l ont prive de sept mois de competition d aout a janvier pour ne disputer que matchs buts "
On retire les lettres isolés et les mots “vides” tel “quand, comme, hors …”
stopwords_fr <- stopwords("french")
stopwords_fr <- c(stopwords_fr, "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t",
"u","v","w","x","y","z" )
contenu <- tm_map(contenu, removeWords , stopwords_fr)
## Warning in tm_map.SimpleCorpus(contenu, removeWords, stopwords_fr):
## transformation drops documents
contenu[1]$content
## [1] " international francais jeremy menez va rejoindre club bordeaux ligue provenance milan ac sous reserve traditionnelle visite medicale annonce club aquitain dimanche menez troisieme recrue girondins apres milieu monaco jeremy toulalan attaquant guineen bastia francois kamano bordeaux sort pale saison repart ambitions nouvelles entraineur jocelyn gourvennec jouit grosse cote grace six saisons convaincantes guingamp age ans menez compte selections buts chez bleus derniere evoluait depuis deux ans milan ac restait an contrat derniere saison ete perturbee blessures forme sochaux menez fait partie fameuse generation championne europe alors considere comme plus grands espoirs foot francais suite rejoint monaco puis roma pendant quatre saisons avant revenir france paris saint germain aventure parisienne deux titres champion cle pris fin deux ans plus tard retour italie milan ac sein equipe lombarde realise meilleure saison buts inscrits avant etre perturbe blessures dos saison derniere prive sept mois competition aout janvier disputer matchs buts "
Racinisation (sans retirer le premier espace)
contenu <- tm_map(contenu, stemDocument, "french")
## Warning in tm_map.SimpleCorpus(contenu, stemDocument, "french"): transformation
## drops documents
contenu[1]$content
## [1] "international franc jeremy men va rejoindr club bordeau ligu proven milan ac sous reserv traditionnel visit medical annonc club aquitain dimanch men troisiem recru girondin apre milieu monaco jeremy toulalan attaqu guineen basti francois kamano bordeau sort pal saison repart ambit nouvel entraineur jocelyn gourvennec jou gross cot grac six saison convainc guingamp age an men compt select but chez bleus dernier evolu depuis deux an milan ac rest an contrat dernier saison ete perturbe blessur form sochal men fait part fameux gener champion europ alor consider comm plus grand espoir foot franc suit rejoint monaco puis rom pend quatr saison avant reven franc paris saint germain aventur parisien deux titr champion cle pris fin deux an plus tard retour ital milan ac sein equip lombard realis meilleur saison but inscrit avant etre perturb blessur dos saison dernier priv sept mois competit aout janvi disput match but"
contenu <- tm_map(contenu , stripWhitespace)
## Warning in tm_map.SimpleCorpus(contenu, stripWhitespace): transformation drops
## documents
contenu <- tm_map(contenu, content_transformer(gsub), pattern = "^\\s+", replacement = "")
## Warning in tm_map.SimpleCorpus(contenu, content_transformer(gsub), pattern = "^\
## \s+", : transformation drops documents
contenu[1]$content
## [1] "international franc jeremy men va rejoindr club bordeau ligu proven milan ac sous reserv traditionnel visit medical annonc club aquitain dimanch men troisiem recru girondin apre milieu monaco jeremy toulalan attaqu guineen basti francois kamano bordeau sort pal saison repart ambit nouvel entraineur jocelyn gourvennec jou gross cot grac six saison convainc guingamp age an men compt select but chez bleus dernier evolu depuis deux an milan ac rest an contrat dernier saison ete perturbe blessur form sochal men fait part fameux gener champion europ alor consider comm plus grand espoir foot franc suit rejoint monaco puis rom pend quatr saison avant reven franc paris saint germain aventur parisien deux titr champion cle pris fin deux an plus tard retour ital milan ac sein equip lombard realis meilleur saison but inscrit avant etre perturb blessur dos saison dernier priv sept mois competit aout janvi disput match but"
Vectorisation
Nous ne gardons que les mots avec 1000 occurences minimum
Le traitement de text effectué, on re-ajoute les données au tableau data pour comparer le texte de départ et le texte obtenu :
Le texte obtenu est correct.
Combien de fois les mots (variables) ont d’occurence dans le contenu des articles ?
summary(colSums(base_modele))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1000 1228 1612 2229 2491 18858
On remarque une médiane à 1612 la haute valeur du maximum est surement dû à des mots vides (stop words) non retirer. Nous étudierons un modèle avec moins de variables (mots) dans une prochaine partie.
Testons notre hypothèse des stop words non retirer, en effet, il pourrait s’agir de mots apparaissant beaucoup dans une certaine catégorie d’articles. Regardons dans combien d’articles les mots sont référencés (sur 10k articles)
occurences <- apply(base_modele, 2, function(x) sum(x>0))
summary(occurences)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 364.0 871.5 1101.0 1392.7 1676.5 6237.0
Un maximum à 6237, soit 2/3 des documents. Nous verrons l’importance de ces mots dans le modèle lorsque nous réaliserons un modèle supervisé avec un maximum de 25 variables.
On construit alors notre modèle avec les catégories et les mots en variables.
base_modelisation = cbind.data.frame(data, base_modele)
base_modelisation = base_modelisation[,-2]
base_modelisation = base_modelisation[,-2]
#On prépare le jeu à 25 variables
#Somme <- colSums(base_modele)
#garder <- which(Somme > median(Somme))
Variables à expliquer : culture, economie, planete, politique, societe, sport.
439 Variables explicatives : les mots qui apparaissent plus de 1000 fois.
A noter que nous n’effectuons que les dernières partie d’un projet de Data Science, puisque les données nous ont été fournis.
Avant de réaliser des modèles de prédictions, détaillons le jeu de données transformé obtenu. Notre plus grande menace serait une corrélation globale de nos variables.
Visualisons graphiquement si nos variables sont très corrélés avec une heatmap :
Les variables sont très peu corrélés,
Pour complèter cela, on réalise une analyse en composante principale avec la catégorie en variable qualitative, ainsi en affichant les ellipse nous verrons les catégories qui s’opposent et quelles variables (les mots dans notre cas) sont les plus responsables des axes, autrement dit les plus importants.
#ces deux lignes sont marginales et ne permettent pas de ce centrer sur les individus.
base_modelisation_ACP <- base_modelisation[-c(8808,5857), ]
library(FactoMineR)
res.pca = PCA(base_modelisation_ACP, scale.unit=TRUE, ncp=5, quali.sup=1, graph=T)
plot.PCA(res.pca, axes=c(1, 2), choix="ind", habillage=1,label="var")
#Essayons de dégager une tendance avec les catégories
library("factoextra")
fviz_pca_ind(res.pca, geom.ind = "point", col.ind = base_modelisation_ACP$category,
palette = c("#00AFBB", "#E7B800", "#FC4E07", "#33FF5E","#CC33FF", "#FFC233" ),
addEllipses = TRUE, ellipse.type = "confidence",
legend.title = "Catégorie de l'article"
)
Les deux premières dimensions ne rendent compte que de 10% de la variance, les graphiques sont inexploitables. Nous pouvons affirmer que les données sont très dispersés, leur non-corrélation est très forte.
Une fois la non-corrélation globale de nos variables assurés, Examinons graphiquement grâce à la librairie wordcloud les mots les plus fréquents par catégorie par un nuage de mots.
#Preparation des données pour le nuage des catégories
# on concatene tout le texte , on sélectionne la catégorie sport et spécicifie content_modif pour là où on prend le texte.
motSport <- paste(data[data$category=="sport",'content_modif'],collapse=' ')
motSociete <- paste(data[data$category=="societe",'content_modif'],collapse=' ')
motEconomie <- paste(data[data$category=="economie",'content_modif'],collapse=' ')
motCulture <- paste(data[data$category=="culture",'content_modif'],collapse=' ')
motPolitique <- paste(data[data$category=="politique",'content_modif'],collapse=' ')
motPlanete <- paste(data[data$category=="planete",'content_modif'],collapse=' ')
# on compte chaque mot, le motif entre guillemet veut dire qu'on coupe la #chainedecaractère quelque soit le nombre d'espaces entre les mots, decreasing en true car il faut montrer les most les plus fréquents , donc on met en décroissant (voir la doc de sort)
motsFreqSport <- data.frame(sort(table(strsplit(motSport,"\\s+")),decreasing = TRUE ))
motsFreqSociete <- data.frame(sort(table(strsplit(motSociete,"\\s+")),decreasing = TRUE ))
motsFreqEconomie <- data.frame(sort(table(strsplit(motEconomie,"\\s+")),decreasing = TRUE ))
motsFreqCulture <- data.frame(sort(table(strsplit(motCulture,"\\s+")),decreasing = TRUE ))
motsFreqPolitique <- data.frame(sort(table(strsplit(motPolitique,"\\s+")),decreasing = TRUE ))
motsFreqPlanete <- data.frame(sort(table(strsplit(motPlanete,"\\s+")),decreasing = TRUE ))
Création des nuages de mots
Sport
wordcloud2(data = motsFreqSport[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")
Societe
wordcloud2(data = motsFreqSociete[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")
Economie
wordcloud2(data = motsFreqEconomie[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")
Culture
wordcloud2(data = motsFreqCulture[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")
Politique
wordcloud2(data = motsFreqPolitique[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")
Planete
wordcloud2(data = motsFreqPlanete[1:500,],minSize = 5, size = 3,shape = 'star',color = "random-light", backgroundColor = "grey")
De nombreux mots semblent spécifiques à une seule catégorie, nous devrions obtenir de bons indicateurs de prédiction.
Avant de passer à la partie suivante, supprimons les données que nous n’utiliserons plus
Apprentissage supervisé: expliquer/prédire une sortie Y à partir d’entrées X Nous devons éviter le sur-apprentissage.
Modèle supervisé pouvant être utilisé : CART , Randomforest, Validation croisée
On commence par construire un modèle d’apprentissage, composé de 80% des lignes de base_modelisation. Le jeu de test est quand à lui fourni.
nb_lignes <- sample(1:nrow(base_modelisation), nrow(base_modelisation)*0.80)
Modélisation : Arbre, algorithme : CART Notre premier modèle est un arbre de décision.
Le principe est que, tant qu’on a pas atteind la taille minimal de noeuds enfants on recherche un seuil qui permet de séparer le noeud parents en 2 noeuds enfants en maximisant notre critère de répartition/de fractionnement.
Notre critère de répartition est le GINI, il est par défaut dans la fonction rpart.
On prend un cp choisi arbitrairement.
tree <-rpart(category~. ,
data = base_modelisation[nb_lignes,],
cp=0,
minsplit = 10
# ,control = rpart.control(minsplit = 10)
)
visTree(tree)
On recherche le cp optimal.
plotcp(tree)
On affine la prédiction en choisissant l’arbre avec l’erreur de prédiction la plus basse
Meilleur <- which.min(tree$cptable[,"xerror"])
cpBest <- tree$cptable[Meilleur, "CP"]
ArbreChoisi <- prune(tree, cp = cpBest)
visTree(ArbreChoisi)
#Mauvaise méthode puisque le meilleur cp change d'une exécution à l'autre du code
#Besttree <-rpart(category~. ,
# data = base_modelisation[nb_lignes,],
# cp=8e-04,
# minsplit = 10
# ,control = rpart.control(minsplit = 10)
# )
#visTree(Besttree)
#print(Besttree$cptable)
#attributes(Besttree)
#construction plot
#plot(Besttree)
#text(Besttree, use.n=T)
Evaluation, matrice de confusion :
prediction_categorie <- predict(ArbreChoisi,
newdata=base_modelisation[-nb_lignes,],
# newdata=test,
#trouver un moyen d'utiliser le jeu de test
type= "class"
)
length(prediction_categorie)
## [1] 2000
conf <- confusionMatrix(data=prediction_categorie, reference = base_modelisation[-nb_lignes,]$category)
conf
## Confusion Matrix and Statistics
##
## Reference
## Prediction culture economie planete politique societe sport
## culture 321 48 49 31 121 57
## economie 29 207 33 26 53 11
## planete 3 1 22 1 7 2
## politique 11 30 18 132 56 9
## societe 36 75 39 77 300 12
## sport 11 14 9 8 12 129
##
## Overall Statistics
##
## Accuracy : 0.5555
## 95% CI : (0.5334, 0.5774)
## No Information Rate : 0.2745
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.4435
##
## Mcnemar's Test P-Value : < 2.2e-16
##
## Statistics by Class:
##
## Class: culture Class: economie Class: planete
## Sensitivity 0.7810 0.5520 0.1294
## Specificity 0.8074 0.9065 0.9923
## Pos Pred Value 0.5120 0.5766 0.6111
## Neg Pred Value 0.9345 0.8976 0.9246
## Prevalence 0.2055 0.1875 0.0850
## Detection Rate 0.1605 0.1035 0.0110
## Detection Prevalence 0.3135 0.1795 0.0180
## Balanced Accuracy 0.7942 0.7292 0.5609
## Class: politique Class: societe Class: sport
## Sensitivity 0.4800 0.5464 0.5864
## Specificity 0.9281 0.8353 0.9697
## Pos Pred Value 0.5156 0.5566 0.7049
## Neg Pred Value 0.9180 0.8296 0.9499
## Prevalence 0.1375 0.2745 0.1100
## Detection Rate 0.0660 0.1500 0.0645
## Detection Prevalence 0.1280 0.2695 0.0915
## Balanced Accuracy 0.7041 0.6909 0.7780
AUC
library(ROCR)
library(pROC)
## Type 'citation("pROC")' for a citation.
##
## Attachement du package : 'pROC'
## Les objets suivants sont masqués depuis 'package:stats':
##
## cov, smooth, var
p1 <- predict(ArbreChoisi, newdata=base_modelisation[-nb_lignes,], type= "prob")[,1]
length(base_modelisation[-nb_lignes,]$category)
## [1] 2000
auc(base_modelisation[-nb_lignes,]$category, p1)
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.8751
Un Auc de 0.88 a été obtenu avec notre jeu test.
#Visualisation de la prédiction
plot(p1 ~ category, data=base_modelisation[-nb_lignes,], xlab="Observe",
ylab="Predis")
Modélisation : Random Forest, algorithme de bagging
Le principe est de créer n arbres non corrélés entre eux puis faire voter chacun d’entre eux.
Pour faire varier un arbre on sélectionne une partie différente des données à chaque noeud et ne construisant des arbres que sur une partie des individus
Nous commencons avec les paramètres suivants : - mtry : 20 - nbtree: 100
Le paramètre mtry représente le nombre de variables échantillonnées de façon aléatoire comme candidats à chaque fractionnement. et nbtree est le nombre d’arbres générés.
#proximité entre les lignes calculés
modele_rf = randomForest(category~.
, data=base_modelisation[nb_lignes,],
importance = T,
proximity=TRUE,
ntree = 100)
plot(modele_rf)
#modele_rf <- randomForest(x=base_modelisation[nb_lignes,-58],
# y = base_modelisation[nb_lignes,58],
# ntree=100
#,proximity=TRUE
#print(modele_rf)
#modele_rf
#plot(modele_rf)
Prediction
p2 <- predict(modele_rf, newdata=base_modelisation[-nb_lignes,], type= "prob")[,1]
Test Prediction
table(p2, base_modelisation[-nb_lignes,]$category)[1,]
## culture economie planete politique societe sport
## 0 0 0 3 2 0
Fréquence conditionel
table(predict(modele_rf), base_modelisation[nb_lignes,]$category)
##
## culture economie planete politique societe sport
## culture 1547 156 144 93 325 157
## economie 71 867 124 109 194 19
## planete 1 0 50 2 2 2
## politique 32 79 40 642 144 11
## societe 141 264 220 257 1611 82
## sport 20 15 4 5 14 556
#plot(margin(modele_rf, base_modelisation[-nb_lignes,]$category))
AUC
length(base_modelisation[-nb_lignes,]$category)
## [1] 2000
auc(base_modelisation[-nb_lignes,]$category, p2)
## Warning in roc.default(response, predictor, auc = TRUE, ...): 'response'
## has more than two levels. Consider setting 'levels' explicitly or using
## 'multiclass.roc' instead
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.9295
Un AUC de 0.92 a été obtenu avec notre jeu de test.
#Visualisation de la prédiction
plot(p2 ~ category, data=base_modelisation[-nb_lignes,], xlab="Observe",
ylab="Predis")
Ce modèle nécessite de réaliser plusieurs modèles d’un des modèles précédent, nous choisissons le modèle de random Forest, observons combien faut-il de temps pour calculer 100 arbres à mon ordinateur.
debut <- Sys.time()
cent = randomForest(category~.
, data=base_modelisation[nb_lignes,],
importance = T,
ntree = 100)
TempsCent <- Sys.time() - debut
print(paste("Pour cent arbres, il faut : ", TempsCent))
## [1] "Pour cent arbres, il faut : 2.34681801398595"
1 minute et 45 secondes !
En 3h, il y a 180 minutes, je peux donc générer 10 000 arbres en 3h. et en 20 minutes je peux en calculer 1000. Commençons par l’option à 1000 arbres.
Créons plusieurs modèle avec des mtry allant de 1 variables à toutes. En tout 50 configurations seront testés.
mtry_expand = expand.grid( .mtry = seq(from = 1, to = (ncol(base_modelisation[nb_lignes,])-1), length.out = 50))
#length.out : premier multiplieur
On créé un grand nombre d’arbres par random forest, avec des configurations différentes du mtry, et grace à la librairie doSNOW on execute 4 fois le code afin d’obtenir une validation croisée.
require(caret)
require(doSNOW)
## Le chargement a nécessité le package : doSNOW
## Le chargement a nécessité le package : foreach
## Le chargement a nécessité le package : iterators
## Le chargement a nécessité le package : snow
#parametre du cv
cv.cntrl <- trainControl(method = "cv",
number = 4,
search = "grid")
#on cree des instances , càd le nbre de fois que l'on execute le programme,
#mon processeur a 4 coeurs, je mets donc 4,
# il s'agira donc d'une validation croisée de degré 4.
# il s'agit de notre deuxième multiplieur
cl <- makeCluster(4,
type = "SOCK")
registerDoSNOW(cl)
set.seed(1234)
#méthode CART
# modele3 <- train(x = base_modelisation[nb_lignes,][,names(base_modelisation[nb_lignes,]) != 'category'],
# y = base_modelisation[nb_lignes,]$category,
# method = 'rpart', trControl = cv.cntrl,
# tuneGrid = mtry_expand, metric = "Accuracy")
#méthode random forest
modele3 <- train(x = base_modelisation[nb_lignes,][,names(base_modelisation[nb_lignes,]) != 'category'],
y = base_modelisation[nb_lignes,]$category,
method = 'rf', trControl = cv.cntrl,
tuneGrid = mtry_expand, metric = "Accuracy",
ntree = 5)
#ntree est notre dernier multiplieur.
# Processing is done, stop the cluster
stopCluster(cl)
#On calcule ainsi length.out x nbre de clust x ntree = nbre d'arbres de notre modèle
# 50 x 4 x 5 = 1000
Quel est le meilleur paramètre pour mtry
modele3_mtry <- modele3$bestTune$mtry
#modele3_best <- modele3$results %>% filter(mtry==modele3_mtry)
#le meilleur mtry est de :
modele3_mtry
## [1] 376.4286
On affiche le modèle obtenu
plot(modele3)
plot(modele3$finalModel$predicted)
Prédiction
library(ROCR)
library(pROC)
p3 <- predict(modele3, newdata=base_modelisation[-nb_lignes,], type= "prob")
p3 <- p3[,1]
Matrice de confusion
MatriceConfu3 <- confusionMatrix(data = modele3$finalModel$predicted,
reference = base_modelisation[nb_lignes,]$category)
#labels <- c("Precision", "Recall", "F1", "Accuracy", "Kappa")
#confu3 <- MatriceConfu3$byClass[labels[1:3]]
#confu3 <- c(confu3, MatriceConfu3$overall[labels[4:5]])
MatriceConfu3
## Confusion Matrix and Statistics
##
## Reference
## Prediction culture economie planete politique societe sport
## culture 1207 178 148 127 402 161
## economie 121 578 105 123 285 57
## planete 46 95 92 47 120 19
## politique 58 129 45 458 251 28
## societe 165 233 103 230 968 58
## sport 35 28 20 17 53 418
##
## Overall Statistics
##
## Accuracy : 0.5162
## 95% CI : (0.5046, 0.5278)
## No Information Rate : 0.2884
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.3942
##
## Mcnemar's Test P-Value : < 2.2e-16
##
## Statistics by Class:
##
## Class: culture Class: economie Class: planete
## Sensitivity 0.7396 0.46575 0.17934
## Specificity 0.8178 0.88420 0.95116
## Pos Pred Value 0.5430 0.45548 0.21957
## Neg Pred Value 0.9147 0.88837 0.93799
## Prevalence 0.2264 0.17217 0.07117
## Detection Rate 0.1675 0.08019 0.01276
## Detection Prevalence 0.3084 0.17605 0.05813
## Balanced Accuracy 0.7787 0.67497 0.56525
## Class: politique Class: societe Class: sport
## Sensitivity 0.45709 0.4656 0.56410
## Specificity 0.91766 0.8462 0.97634
## Pos Pred Value 0.47265 0.5509 0.73205
## Neg Pred Value 0.91281 0.7962 0.95133
## Prevalence 0.13901 0.2884 0.10280
## Detection Rate 0.06354 0.1343 0.05799
## Detection Prevalence 0.13443 0.2438 0.07922
## Balanced Accuracy 0.68737 0.6559 0.77022
AUC
length(base_modelisation[-nb_lignes,]$category)
## [1] 2000
auc(base_modelisation[-nb_lignes,]$category, p3)
## Warning in roc.default(response, predictor, auc = TRUE, ...): 'response'
## has more than two levels. Consider setting 'levels' explicitly or using
## 'multiclass.roc' instead
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.8696
Un Auc de 0.89 a été trouver avec notre jeu de test, c’est moins bien que notre deuxième modèle. Il doit exister un moyen d’optimiser cela.
#Visualisation de la prédiction
plot(p3 ~ category, data=base_modelisation[-nb_lignes,], xlab="Observe",
ylab="Predis")
A REDIGER
On sélectionne les 25 variables les plus importantes parmis le 2ème modèle (random Forest) Ainsi qu’une visualisation graphique de leur importance.
#class (modele_rf$importance[order(modele_rf$importance[,1], decreasing = TRUE)[1:25], ])
#"matrix" "array"
modele_rf$importance[order(modele_rf$importance[,1], decreasing = TRUE)[1:25], ]
## culture economie planete politique societe
## film 0.03779862 0.0101769627 1.970205e-03 6.917695e-03 0.0052767906
## selon 0.03682235 -0.0033766209 5.969326e-04 6.722209e-04 -0.0040805528
## loi 0.03510184 0.0018723104 8.776673e-04 1.176114e-02 -0.0020204313
## president 0.03254492 0.0025733510 -6.818821e-04 4.018785e-03 0.0001095394
## entrepris 0.03059897 0.0108422843 6.059467e-05 4.510012e-03 0.0028626525
## euros 0.02911506 0.0073409536 2.131236e-04 4.220319e-03 0.0018500476
## scen 0.02606563 0.0095775789 3.206675e-03 2.670347e-03 0.0052180034
## ete 0.02551715 0.0024753406 -5.947861e-03 1.764606e-03 -0.0018503198
## ministr 0.02441432 0.0080520537 1.842779e-03 6.285404e-03 -0.0019171661
## festival 0.02195785 0.0044679688 1.761555e-03 4.984302e-03 0.0062098429
## contr 0.01873302 0.0034327927 1.341459e-03 4.206246e-04 -0.0015698615
## art 0.01850906 0.0044264773 2.212927e-04 2.814519e-03 0.0050032630
## plus 0.01792733 -0.0011945951 -1.299601e-03 -1.770111e-04 -0.0030120290
## franc 0.01753846 0.0002589011 -2.659020e-03 8.116099e-04 -0.0009798408
## person 0.01704772 -0.0003942590 1.412098e-03 1.604334e-03 0.0001234612
## econom 0.01665677 -0.0005294370 1.538815e-03 5.030611e-03 0.0025616114
## equip 0.01569333 0.0008414676 5.739601e-04 3.058271e-03 0.0028193848
## droit 0.01553114 0.0013362256 9.065263e-04 6.537585e-03 -0.0026760642
## match 0.01473064 0.0054755511 3.172074e-03 2.928522e-03 0.0057535165
## gouvern 0.01432893 0.0030974688 4.399077e-04 8.084119e-03 -0.0006023529
## mard 0.01386552 0.0008791362 -1.404762e-03 1.869725e-05 -0.0045630821
## general 0.01277326 -0.0020200683 1.264251e-04 3.992878e-04 -0.0001867260
## etat 0.01189911 -0.0012837380 4.058272e-04 3.909779e-04 -0.0003448217
## final 0.01152647 0.0030227986 1.083431e-03 8.666551e-04 0.0014849358
## salar 0.01098601 0.0011872891 3.687099e-05 2.829448e-03 0.0005789450
## sport MeanDecreaseAccuracy MeanDecreaseGini
## film 9.323085e-03 0.013904239 121.73817
## selon 6.583245e-03 0.007406092 33.41306
## loi 1.554878e-02 0.011009433 54.11748
## president 3.594765e-03 0.008718757 37.66749
## entrepris 1.444357e-02 0.011737164 66.43167
## euros 5.516489e-03 0.009565224 48.31213
## scen 3.160252e-03 0.009967536 96.50719
## ete 3.289099e-04 0.005526061 37.21730
## ministr 9.819286e-03 0.008306189 45.13795
## festival 4.807438e-03 0.008828925 87.73417
## contr 1.305475e-03 0.004689947 29.85610
## art 5.491040e-03 0.007360796 66.01131
## plus -1.546640e-03 0.002761880 31.31160
## franc -3.438295e-03 0.003292100 30.83563
## person 2.789247e-03 0.004411981 26.40602
## econom 6.465474e-03 0.005890631 34.49277
## equip 2.736063e-02 0.007805329 52.61598
## droit 9.508637e-05 0.003970888 25.68902
## match 7.857125e-02 0.014721566 111.23249
## gouvern 7.610276e-03 0.005542942 33.19277
## mard -3.666819e-04 0.001842740 14.97844
## general 1.635510e-03 0.002719767 18.64439
## etat 2.716745e-03 0.002734150 21.34128
## final 1.743296e-02 0.005540303 46.79316
## salar 2.770249e-03 0.003551707 21.84534
varImpPlot(modele_rf)
#copie des termes dans l'attente de trouver une méthode pour récup les variables d'une matrice.
modele_25 = randomForest(category~ selon + film + loi + entrepris + president + ete + ministr + festival + scen + gouvern + contr + franc + match + person + art + general + social + equip + droit + national + etat + final + econom + plac
, data=base_modelisation[nb_lignes,],
importance = T,
proximity=TRUE,
ntree = 100)
plot(modele_25)
Prediction
p4 <- predict(modele_25, newdata=base_modelisation[-nb_lignes,], type= "prob")[,1]
Test Prediction
table(p4, base_modelisation[-nb_lignes,]$category)[1,]
## culture economie planete politique societe sport
## 2 24 7 23 21 29
Fréquence conditionel
table(predict(modele_25), base_modelisation[nb_lignes,]$category)
##
## culture economie planete politique societe sport
## culture 1487 256 171 122 429 186
## economie 100 644 94 113 273 38
## planete 3 2 5 7 11 2
## politique 32 116 55 476 234 16
## societe 165 324 250 379 1311 76
## sport 25 39 7 11 32 509
AUC
length(base_modelisation[-nb_lignes,]$category)
## [1] 2000
auc(base_modelisation[-nb_lignes,]$category, p4)
## Warning in roc.default(response, predictor, auc = TRUE, ...): 'response'
## has more than two levels. Consider setting 'levels' explicitly or using
## 'multiclass.roc' instead
## Setting levels: control = culture, case = economie
## Setting direction: controls > cases
## Area under the curve: 0.8803
Une perte d’environ 0.006 d’AUC pour un passage de 440 variables à 25. Cette perte est négligable
#Visualisation de la prédiction
plot(p2 ~ category, data=base_modelisation[-nb_lignes,], xlab="Observe",
ylab="Predis")
Nos 3 modèles sont utilisables. La forte réduction du nombre de variable sur le modèle randomForest a eu un impact mineur sur l’AUC.